﻿using System;
using System.IO;
using System.IO.Compression;
using System.Text;

namespace xxpl.Utils
{
    public class XorEncryptor
    {
        private byte key;

        public byte Key
        {
            get { return key; }
            set { key = value; }
        }

        public XorEncryptor()
        {
            Random keyRandom = new Random();
            key=(byte)keyRandom.Next(256);
        }

        public void Encrypt(byte[] value)
        {
            Encrypt(value, 0, value.Length);
        }

        public void Encrypt(byte[] value, int offset, int len)
        {
            for (int i = offset; i < offset + len; i++)
            {
                value[i] ^= key;
            }
        }
    }
    public class DataZipStream:GZipStream
    {
        private bool keySpecify;
        private readonly XorEncryptor ep=new XorEncryptor();

        public DataZipStream(Stream stream, CompressionMode mode) : base(stream, mode)
        {
        }

        public DataZipStream(Stream stream, CompressionMode mode, bool leaveOpen) : base(stream, mode, leaveOpen)
        {
        }

        public void WriteBlock(string value)
        {
            byte[] block = Encoding.ASCII.GetBytes(value);
            WriteBlock(block);
        }

        public void WriteBlock( byte[] block)
        {
            if(block==null||block.Length==0)
            {
                return;
            }
            Write(BitConverter.GetBytes(block.Length), 0, 4);
            Write(block, 0, block.Length);
        }

        public override void Write(byte[] array, int offset, int count)
        {
            if (!keySpecify)
            {
                keySpecify = true;
                Byte[] keyArray=new byte[1];
                keyArray[0] = ep.Key;
                base.Write(keyArray, offset, 1);
            }

            ep.Encrypt(array,offset,count);

            base.Write(array, offset, count);
        }

        public string ReadBlockString()
        {
            byte[] value = ReadBlockByte();
            if (value != null)
            {
                return Encoding.ASCII.GetString(value);
            }
            return string.Empty;
        }

        public byte[] ReadBlockByte()
        {
            int size = ReadInt();
            byte[] value = new byte[size];
            int result = Read(value, 0, size);
            
            if (result==size)
            {
                return value;
            }
            if(result==0)
                return null;
            throw new IOException("net word error");
        }

        public int ReadInt()
        {
            byte[] x = new byte[4];
            int result = Read(x, 0, 4);
            if (result==4)
            {
                return BitConverter.ToInt32(x, 0);
            }
            
            if(result==0)
                return 0;
            throw new IOException("net word error");
        }

        public override int Read(byte[] array, int offset, int count)
        {
            if (!keySpecify)
            {
                keySpecify = true;
                base.Read(array, offset, 1);
                ep.Key= array[offset];
            }
            int result = base.Read(array, offset, count);
            
            ep.Encrypt(array,offset,result);
            
            return result;
        }
    }
}
